home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 November
/
EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso
/
earcd
/
misc
/
excalc1.lha
/
ExCalcV1.1
/
Source
/
Calculator.mod
next >
Wrap
Text File
|
1995-05-08
|
21KB
|
687 lines
(*********************************************************************)
(* *)
(* Module Calculator Copyright © 1995 by Computer Inspirations *)
(* *)
(* Design : Michael Griebling *)
(* Change : Original *)
(* *)
(*********************************************************************)
MODULE Calculator;
IMPORT arg: Arguments, Cnv: Conversions, XI: ExIntegers, X: ExNumbers,
XM: ExMathLib0, io, iox: InOutExt, f: FileSystem, s: Strings,
Break;
TYPE
Tokens = INTEGER;
CONST
(* Tokens definitions *)
Empty = 0;
(* expression tokens *)
Plus = 1;
Minus = 2;
Or = 3;
Xor = 4;
StoreMem = 5;
(* term tokens *)
Times = 6;
Divide = 7;
ShiftLeft = 8;
And = 9;
Mod = 10;
Div = 11;
ClearBit = 12;
SetBit = 13;
ToggleBit = 14;
AShiftRight = 15;
RotateRight = 16;
RotateLeft = 17;
ShiftRight = 18;
(* power tokens *)
Power = 19;
PercentOf = 20;
Root = 21;
Squared = 22;
Cubed = 23;
Inverse = 24;
Factorial = 25;
(* miscellaneous tokens *)
LeftBrace = 26;
RightBrace = 27;
PowerOfe = 28;
Sin = 29;
Cos = 30;
Tan = 31;
ArcSin = 32;
ArcCos = 33;
ArcTan = 34;
Sinh = 35;
Cosh = 36;
Tanh = 37;
ArcSinh = 38;
ArcCosh = 39;
ArcTanh = 40;
Not = 41;
Base = 42;
Digits = 43;
Pi = 44;
NaturalLog = 45;
SquareRoot = 46;
CubeRoot = 47;
Decimals = 48;
Notation = 49;
Complement = 50;
Log = 51;
Number = 52;
DegRadGrad = 53;
MemoryCell = 54;
CONST
MaxMemory = 15;
StrSize = 250;
Space = ' ';
PunctuationChars = ",'_";
StateFile = "RAM:CalculatorState.bin";
(* DegRadType definitions *)
Degrees = 0;
Radians = 1;
Gradians = 2;
TYPE
String = ARRAY StrSize OF CHAR;
SymbolArray = ARRAY MaxMemory+1 OF X.ExNumType;
DegRadType = SHORTINT;
StateType = RECORD
LocalBase : XI.BaseType;
DecPoint : INTEGER;
SciNotation : BOOLEAN;
NumbDigits : INTEGER;
LastAnswer : X.ExNumType;
DegRadFlag : DegRadType;
SymbolTable : SymbolArray;
END;
VAR
Token : Tokens;
NumberValue : X.ExNumType;
Answer : X.ExNumType;
ToGradians : X.ExNumType;
FromGradians: X.ExNumType;
State : StateType; (* Calculator state *)
ResultStr,
CommandLine : String;
PROCEDURE SaveState;
VAR
RFile : f.File;
BEGIN
(* save calculator state *)
IF f.Open(RFile, StateFile, TRUE) &
f.Write(RFile, State) &
f.Close(RFile) THEN END;
END SaveState;
PROCEDURE GetState;
VAR
Loc : INTEGER;
RFile : f.File;
BEGIN
(* default calculator state *)
State.LocalBase := 10;
State.DecPoint := 0;
State.SciNotation := FALSE;
State.NumbDigits := 52;
State.DegRadFlag := Degrees;
FOR Loc := 0 TO MaxMemory DO
State.SymbolTable[Loc] := X.Ex0;
END;
(* get new state -- if available *)
IF f.Open(RFile, StateFile, FALSE) THEN
IF f.Read(RFile, State) & f.Close(RFile) THEN
X.SetMaxDigits(State.NumbDigits);
END;
END;
END GetState;
PROCEDURE UnsignInt (Number : ARRAY OF CHAR;
VAR Result : X.ExNumType);
(* $CopyArrays- *)
VAR
numb : X.ExNumType;
done : BOOLEAN;
BEGIN
(* perform the actual conversion from string to number *)
IF State.LocalBase = 10 THEN
X.StrToExNum(Number, numb);
done := X.ExStatus = X.Okay;
ELSIF (State.LocalBase > 1) & (State.LocalBase <= 16) THEN
XI.StrToExInt(Number, State.LocalBase, numb);
done := X.ExStatus = X.Okay;
ELSE
done := FALSE;
END;
IF done THEN (* all went OK *)
Result := numb;
ELSE
X.ExStatus := X.IllegalNumber;
Result := X.Ex0;
END;
END UnsignInt;
PROCEDURE LocateChar(Str : ARRAY OF CHAR; ch : CHAR;
start : LONGINT) : LONGINT;
(* $CopyArrays- *)
VAR Find : ARRAY 2 OF CHAR;
BEGIN
Find[0] := ch; Find[1] := 0X;
RETURN s.OccursPos(Str, Find, start);
END LocateChar;
PROCEDURE ExtractNumber(VAR arg : ARRAY OF CHAR;
VAR NumberValue : X.ExNumType);
VAR
Constant : String;
NumChars : ARRAY 20 OF CHAR;
NumberChars : ARRAY 20 OF CHAR;
ConIndex : INTEGER;
PROCEDURE GetNumber();
BEGIN
LOOP
(* gather number characters *)
IF LocateChar(NumChars, arg[0], 0) # -1 THEN
(* not punctuation character *)
Constant[ConIndex] := arg[0];
INC(ConIndex);
IF (arg[0] = 'E') & (State.LocalBase = 10) THEN
IF (arg[1] = '+') OR (arg[1] = '-') THEN
Constant[ConIndex] := arg[1];
INC(ConIndex);
s.Delete(arg, 0, 1);
END;
s.Delete(NumChars, 0, 1); (* remove `.' *)
END;
s.Delete(arg, 0, 1);
ELSIF LocateChar(PunctuationChars, arg[0], 0) # -1 THEN
s.Delete(arg, 0, 1);
ELSE
EXIT;
END;
IF arg[0] = 0X THEN EXIT END;
END;
END GetNumber;
BEGIN
Constant := "";
ConIndex := 0;
NumberChars := ".E0123456789ABCDEF";
(* valid number characters *)
IF State.LocalBase = 10 THEN
s.Cut(NumberChars, 0, 12, NumChars);
ELSE
s.Cut(NumberChars, 2, State.LocalBase+2, NumChars);
END;
(* get a number string from the input *)
GetNumber();
Constant[ConIndex] := 0X; (* terminate the new string *)
(* convert to an ExNumber *)
IF ConIndex > 0 THEN
UnsignInt(Constant, NumberValue);
ELSE
NumberValue := X.Ex0;
X.ExStatus := X.IllegalNumber; (* illegal number or constant *)
END;
END ExtractNumber;
PROCEDURE StoreMemory(Location, Value : X.ExNumType);
(* Store the `Value' argument in the `Location' memory cell. *)
VAR
Loc : LONGINT;
BEGIN
Loc := X.ExToLongInt(Location);
IF Loc <= MaxMemory THEN
State.SymbolTable[Loc] := Value;
ELSE
X.ExStatus := X.UndefinedStorage; (* unknown memory cell *)
END;
END StoreMemory;
PROCEDURE RecallMemory(Location : X.ExNumType; VAR Value : X.ExNumType);
(* Recall the contents of the `Location' memory cell and return *)
VAR
Loc : LONGINT;
BEGIN
Loc := X.ExToLongInt(Location);
IF Loc <= MaxMemory THEN
Value := State.SymbolTable[Loc];
ELSE
X.ExStatus := X.UndefinedStorage; (* unknown memory cell *)
Value := X.Ex0;
END;
END RecallMemory;
PROCEDURE ToRadians (InAngle : X.ExNumType; VAR Result : X.ExNumType);
(* Convert from another angular representation to radians -- depending on
the state of the `DegRadFlag' *)
BEGIN
IF State.DegRadFlag = Degrees THEN
Result := InAngle;
XM.DegToRadX(Result);
ELSIF State.DegRadFlag = Gradians THEN
X.ExMult(Result, FromGradians, InAngle);
ELSE
Result := InAngle
END;
END ToRadians;
PROCEDURE FromRadians (InAngle : X.ExNumType;
VAR Result : X.ExNumType);
(* Convert to another angular representation from radians --
depending on the state of the `DegRadFlag' *)
BEGIN
IF State.DegRadFlag = Degrees THEN
Result := InAngle;
XM.RadToDegX(Result)
ELSIF State.DegRadFlag = Gradians THEN
X.ExMult(Result, ToGradians, InAngle);
ELSE
Result := InAngle;
END;
END FromRadians;
PROCEDURE GetToken(VAR arg : ARRAY OF CHAR);
CONST
Sqrd = "\xB2";
Cubd = "\xB3";
Andd = "\xB7";
Tims = "\xD7";
Divd = "\xF7";
Min1 = "\xAD\xB9";
PROCEDURE IsToken(Str : ARRAY OF CHAR;
T : Tokens) : BOOLEAN;
BEGIN
IF s.OccursPos(arg, Str, 0) = 0 THEN
s.Delete(arg, 0, s.Length(Str));
Token := T;
RETURN TRUE;
END;
RETURN FALSE;
END IsToken;
BEGIN
(* delete any blank spaces *)
WHILE arg[0] = Space DO s.Delete(arg, 0, 1); END;
(* form a token *)
IF ((arg[0] >= '0') & (arg[0] <= '9')) OR (arg[0] = '.') THEN
(* token is some sort of number *)
Token := Number;
ExtractNumber(arg, NumberValue);
ELSIF arg[0] = 0X THEN
(* empty string *)
Token := Empty;
ELSE
(* token is a symbol *)
IF IsToken("+", Plus) THEN RETURN END;
IF IsToken("-", Minus) THEN RETURN END;
IF IsToken(Sqrd, Squared) THEN RETURN END;
IF IsToken(Cubd, Cubed) THEN RETURN END;
IF IsToken("x", Times) THEN RETURN END;
IF IsToken(Tims, Times) THEN RETURN END;
IF IsToken("/", Divide) THEN RETURN END;
IF IsToken(Divd, Divide) THEN RETURN END;
IF IsToken("(", LeftBrace) THEN RETURN END;
IF IsToken(")", RightBrace) THEN RETURN END;
IF IsToken("^", Power) THEN RETURN END;
IF IsToken("%", PercentOf) THEN RETURN END;
IF IsToken("!", Factorial) THEN RETURN END;
IF IsToken("&", And) THEN RETURN END;
IF IsToken(Andd, And) THEN RETURN END;
IF IsToken("|", Or) THEN RETURN END;
IF IsToken("e^", PowerOfe) THEN RETURN END;
IF IsToken("e", Number) THEN NumberValue := X.e;
RETURN END;
IF IsToken(Min1, Inverse) THEN RETURN END;
IF IsToken("**", Power) THEN RETURN END;
IF IsToken("*", Times) THEN RETURN END;
IF IsToken("BAS", Base) THEN RETURN END;
IF IsToken("OR", Or) THEN RETURN END;
IF IsToken("Pi", Number) THEN NumberValue := X.pi;
RETURN END;
IF IsToken("SBIT", SetBit) THEN RETURN END;
IF IsToken("SHR", ShiftRight) THEN RETURN END;
IF IsToken("SHL", ShiftLeft) THEN RETURN END;
IF IsToken("SINH", Sinh) THEN RETURN END;
IF IsToken("SIN", Sin) THEN RETURN END;
IF IsToken("SQRT", SquareRoot) THEN RETURN END;
IF IsToken("STM", StoreMem) THEN RETURN END;
IF IsToken("SCI", Notation) THEN RETURN END;
IF IsToken("AND", And) THEN RETURN END;
IF IsToken("ASINH", ArcSinh) THEN RETURN END;
IF IsToken("ASIN", ArcSin) THEN RETURN END;
IF IsToken("ASR", AShiftRight) THEN RETURN END;
IF IsToken("ACOSH", ArcCosh) THEN RETURN END;
IF IsToken("ACOS", ArcCos) THEN RETURN END;
IF IsToken("ATANH", ArcTanh) THEN RETURN END;
IF IsToken("ATAN", ArcTan) THEN RETURN END;
IF IsToken("XOR", Xor) THEN RETURN END;
IF IsToken("MOD", Mod) THEN RETURN END;
IF IsToken("M", MemoryCell) THEN
ExtractNumber(arg, NumberValue); RETURN END;
IF IsToken("LOG", Log) THEN RETURN END;
IF IsToken("LN", NaturalLog) THEN RETURN END;
IF IsToken("DIV", Div) THEN RETURN END;
IF IsToken("DP", Decimals) THEN RETURN END;
IF IsToken("DRG", DegRadGrad) THEN RETURN END;
IF IsToken("CBIT", ClearBit) THEN RETURN END;
IF IsToken("CBRT", CubeRoot) THEN RETURN END;
IF IsToken("COSH", Cosh) THEN RETURN END;
IF IsToken("COS", Cos) THEN RETURN END;
IF IsToken("NOT", Complement) THEN RETURN END;
IF IsToken("ROOT", Root) THEN RETURN END;
IF IsToken("ROL", RotateLeft) THEN RETURN END;
IF IsToken("ROR", RotateRight) THEN RETURN END;
IF IsToken("TANH", Tanh) THEN RETURN END;
IF IsToken("TAN", Tan) THEN RETURN END;
IF IsToken("TBIT", ToggleBit) THEN RETURN END;
IF IsToken("DIG", Digits) THEN RETURN END;
(* Illegal token if we reach here *)
X.ExStatus := X.IllegalOperator;
s.Delete(arg, 0, 1);
END;
END GetToken;
PROCEDURE^ Expression (VAR arg : ARRAY OF CHAR; VAR Result : X.ExNumType);
PROCEDURE Factor (VAR arg : ARRAY OF CHAR; VAR Result : X.ExNumType);
VAR
SaveBase : XI.BaseType;
temp : X.ExNumType;
PROCEDURE Next;
BEGIN
GetToken(arg); Factor(arg, Result);
END Next;
BEGIN
CASE Token OF
LeftBrace : GetToken(arg); Expression(arg, Result);
IF Token = RightBrace THEN GetToken(arg);
ELSE X.ExStatus := X.MismatchBraces END;
| Number : GetToken(arg); Result := NumberValue;
IF Token = Number THEN
X.ExStatus := X.IllegalNumber;
END;
| Complement : Next(); XI.ExOnesComp(Result, Result);
| Sin : Next(); ToRadians(Result, Result);
XM.sinX(Result, Result);
| Cos : Next(); ToRadians(Result, Result);
XM.cosX(Result, Result);
| Tan : Next(); ToRadians(Result, Result);
XM.tanX(Result, Result);
| ArcSin : Next(); XM.arcsinX(Result, Result);
FromRadians(Result, Result);
| ArcCos : Next(); XM.arccosX(Result, Result);
FromRadians(Result, Result);
| ArcTan : Next(); XM.arctanX(Result, Result);
FromRadians(Result, Result);
| Sinh : Next(); XM.sinhX(Result, Result);
| Cosh : Next(); XM.coshX(Result, Result);
| Tanh : Next(); XM.tanhX(Result, Result);
| ArcSinh : Next(); XM.arcsinhX(Result, Result);
| ArcCosh : Next(); XM.arccoshX(Result, Result);
| ArcTanh : Next(); XM.arctanhX(Result, Result);
| SquareRoot : Next(); XM.sqrtX(Result, Result);
| CubeRoot : Next(); X.ExNumb(3, 0, 0, temp);
XM.rootX(Result, Result, temp);
| NaturalLog : Next(); XM.lnX(Result, Result);
| Log : Next(); XM.logX(Result, Result);
| PowerOfe : Next(); XM.expX(Result, Result);
| MemoryCell : GetToken(arg); RecallMemory(NumberValue, Result);
| Base : SaveBase := State.LocalBase;
State.LocalBase := 10;
Next();
State.LocalBase := SHORT(SHORT(X.ExToLongInt(Result)));
IF (State.LocalBase < 2) OR
(State.LocalBase > 16) THEN
State.LocalBase := SaveBase;
END;
Result := State.LastAnswer;
| Digits : Next();
IF X.ExStatus = X.Okay THEN
State.NumbDigits := SHORT(X.ExToLongInt(Result));
X.SetMaxDigits(State.NumbDigits);
State.NumbDigits := X.GetMaxDigits();
Result := State.LastAnswer;
END;
| Decimals : Next();
IF X.ExStatus = X.Okay THEN
State.DecPoint := SHORT(X.ExToLongInt(Result));
Result := State.LastAnswer;
END;
| Notation : GetToken(arg);
State.SciNotation := NOT State.SciNotation;
Result := State.LastAnswer;
| DegRadGrad : GetToken(arg);
IF State.DegRadFlag = Gradians THEN
State.DegRadFlag := Degrees;
ELSE INC(State.DegRadFlag) END;
Result := State.LastAnswer;
ELSE X.ExStatus := X.IllegalOperator;
Result := X.Ex0;
END;
END Factor;
PROCEDURE Powers (VAR arg : ARRAY OF CHAR; VAR Result : X.ExNumType);
VAR
temp : X.ExNumType;
PROCEDURE Next;
BEGIN
GetToken(arg); Factor(arg, Result);
END Next;
BEGIN
Factor(arg, temp);
WHILE (Token >= Power) & (Token <= Factorial) DO
CASE Token OF
Power : Next(); XM.powerX(temp, temp, Result);
| Root : Next(); XM.rootX(temp, Result, temp);
| Squared : GetToken(arg); X.ExMult(temp, temp, temp);
| Cubed : GetToken(arg); XM.xtoi(temp, temp, 3);
| Inverse : GetToken(arg); X.ExDiv(temp, X.Ex1, temp);
| Factorial : GetToken(arg);
XM.factorialX(temp, X.ExToLongInt(temp));
| PercentOf : GetToken(arg);
X.ExNumb(0, 1, -1, Result); (* 0.01 *)
X.ExMult(Result, temp, Result);
Factor(arg, temp);
X.ExMult(temp, temp, Result);
ELSE (* skip token *)
X.ExStatus := X.IllegalOperator;
GetToken(arg);
END;
END;
Result := temp;
END Powers;
PROCEDURE Term (VAR arg : ARRAY OF CHAR; VAR Result : X.ExNumType);
VAR
temp, temp2 : X.ExNumType;
PROCEDURE Next;
BEGIN
GetToken(arg); Powers(arg, Result);
END Next;
PROCEDURE ToCard(Ex : X.ExNumType) : INTEGER;
BEGIN
RETURN SHORT(X.ExToLongInt(Ex));
END ToCard;
BEGIN
Powers(arg, temp);
WHILE (Token >= Times) & (Token <= ShiftRight) DO
CASE Token OF
Times : Next(); X.ExMult(temp, Result, temp);
| Divide : Next(); X.ExDiv(temp, temp, Result);
| Div : Next(); XI.ExIntDiv(temp, temp, Result);
| Mod : Next(); XI.ExMod(temp, temp, Result);
| And : Next(); XI.ExAnd(temp, temp, Result);
| ShiftRight : Next(); XI.ExShr(temp, temp, ToCard(Result));
| AShiftRight : Next(); XI.ExAshr(temp, temp, ToCard(Result));
| RotateRight : Next(); XI.ExRor(temp, temp, ToCard(Result));
| ShiftLeft : Next(); XI.ExShl(temp, temp, ToCard(Result));
| RotateLeft : Next(); XI.ExRol(temp, temp, ToCard(Result));
| ClearBit : Next(); XI.ExClearBit(temp, temp, ToCard(Result));
| SetBit : Next(); XI.ExSetBit(temp, temp, ToCard(Result));
| ToggleBit : Next(); XI.ExToggleBit(temp, temp, ToCard(Result));
ELSE (* skip token *)
GetToken(arg); X.ExStatus := X.IllegalOperator;
END;
END;
Result := temp;
END Term;
PROCEDURE Expression (VAR arg : ARRAY OF CHAR;
VAR Result : X.ExNumType);
VAR
temp : X.ExNumType;
Str : String;
PROCEDURE Next(VAR Result : X.ExNumType);
BEGIN
GetToken(arg); Term(arg, Result);
END Next;
BEGIN
CASE Token OF
Plus : Next(temp);
| Minus : Next(temp); X.ExChgSign(temp);
ELSE Term(arg, temp)
END;
WHILE (Token >= Plus) & (Token <= StoreMem) DO
CASE Token OF
Plus : Next(Result); X.ExAdd(temp, temp, Result);
| Minus : Next(Result); X.ExSub(temp, temp, Result);
| Or : Next(Result); XI.ExOr(temp, Result, temp);
| Xor : Next(Result); XI.ExXor(temp, Result, temp);
| StoreMem : Next(Result); StoreMemory(Result, temp);
ELSE Term(arg, temp);
END;
END;
Result := temp;
END Expression;
PROCEDURE SimpleExpression (VAR arg : ARRAY OF CHAR;
VAR Result : X.ExNumType);
BEGIN
X.ExStatus := X.Okay;(* clear out any previous errors *)
GetToken(arg); (* start things off with the first token *)
Expression(arg, Result);
State.LastAnswer := Result;
END SimpleExpression;
PROCEDURE GetCLI(VAR Str : ARRAY OF CHAR) : BOOLEAN;
BEGIN
IF arg.NumArgs() < 1 THEN
Str := "";
RETURN FALSE;
ELSE
arg.GetArg(1, Str);
RETURN TRUE;
END;
END GetCLI;
PROCEDURE WriteAsString(x : X.ExNumType);
BEGIN
IF State.LocalBase = 10 THEN
IF State.SciNotation THEN
X.ExNumToStr(x, State.DecPoint, 1, ResultStr);
ELSE
X.ExNumToStr(x, State.DecPoint, 0, ResultStr);
END;
ELSE
XI.ExIntToStr(x, State.LocalBase, ResultStr);
END;
IF X.ExStatus = X.Okay THEN
io.WriteString(ResultStr);
ELSE
io.WriteString("Illegal input string!");
END;
io.WriteLn;
END WriteAsString;
BEGIN
(* Local gradian conversion constants *)
X.StrToExNum(
"1.570796326794896619231321691639751442098584699687555E-2",
FromGradians);
X.StrToExNum(
"6.366197723675813430755350534900574481378385829618240E+1",
ToGradians);
Token := Empty;
GetState();
LOOP
IF GetCLI(CommandLine) THEN
SimpleExpression(CommandLine, Answer);
WriteAsString(Answer);
EXIT;
END;
io.WriteString("Calc");
CASE State.DegRadFlag OF
| Degrees : io.Write("D")
| Radians : io.Write("R")
| Gradians : io.Write("G")
END;
IF State.LocalBase # 10 THEN
io.WriteString("Bas");
io.WriteInt(State.LocalBase, 1);
END;
io.WriteString("> ");
iox.ReadLine(CommandLine);
IF s.Length(CommandLine) = 0 THEN
EXIT;
END;
SimpleExpression(CommandLine, Answer);
WriteAsString(Answer);
END;
SaveState();
END Calculator.